home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ETO Development Tools 4
/
ETO Development Tools 4.iso
/
Tools - Objects
/
MacApp
/
MacApp 3.0a2
/
Libraries
/
UFileHandler.cp
< prev
next >
Wrap
Text File
|
1991-05-01
|
19KB
|
766 lines
// UFileHandler.cp
/* Copyright © 1984-1991 by Apple Computer Inc. All rights reserved. */
#ifndef __UFILEHANDLER__
#include <UFileHandler.h>
#endif
#ifndef __STDIO__
#include <StdIo.h>
#endif
#ifndef __GEOMETRY__
#include <Geometry.h>
#endif
#ifndef __PACKAGES__
#include <Packages.h>
#endif
#ifndef __FOLDERS__
#include <Folders.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __UFILE__
#include <UFile.h>
#endif
#ifndef __UAPPLICATION__
#include <UApplication.h>
#endif
#ifndef __UFILEBASEDDOCUMENT__
#include <UFileBasedDocument.h>
#endif
#ifndef __UMACAPPUTILITIES__
#include <UMacAppUtilities.h>
#endif
#ifndef __UERRORMGR__
#include <UErrorMgr.h>
#endif
#ifndef __UMACAPPGLOBALS__
#include <UMacAppGlobals.h>
#endif
//--------------------------------------------------------------------------------------------------
#pragma segment MAOpen
pascal void TFileHandler::Initialize(void) // override
{
inherited::Initialize();
fDocument = NULL;
fFile = NULL;
fFileExists = FALSE;
fHowToSave = svtAskUser;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAOpen
pascal void TFileHandler::IFileHandler(TFileBasedDocument* itsDocument,
TFile* itsFile,
const OSType itsFileType,
const OSType itsCreator,
Boolean usesDataFork,
Boolean usesRsrcFork,
Boolean keepsDataOpen,
Boolean keepsRsrcOpen)
{
FailInfo fi;
VOLATILE(itsFile);
this->IObject();
if (fi.Try())
{
if (keepsDataOpen || keepsRsrcOpen)
fHowToSave = svtAlways;
else
fHowToSave = svtAskUser;
if (itsFile)
itsFile->DefineFile(itsFileType, itsCreator, usesDataFork, usesRsrcFork, keepsDataOpen, keepsRsrcOpen);
fi.Success();
}
else // Recover
{
itsFile = (TFile *)FreeIfObject(itsFile);
fi.ReSignal();
}
fFile = itsFile;
fDocument = itsDocument;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAClose
pascal void TFileHandler::Free(void) // override
{
if (fFile)
{
this->CloseFile();
fFile->Free();
fFile = NULL;
}
inherited::Free();
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::AboutToSaveFile(CmdNumber itsCmd,
Boolean& makingCopy)
{
fDocument->AboutToSaveFile(itsCmd, makingCopy);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MADocumentRes
pascal Boolean TFileHandler::FileAlreadyOpen(TFile* aFile)
{
if (fFileExists)
return fFile->IsSameFile(aFile);
else
return FALSE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MADocumentRes
pascal void TFileHandler::CloseFile(void)
{
OSErr err;
if (fFile)
err = fFile->CloseFile(TRUE);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::DoNeedDiskSpace(long& dataForkBytes,
long& rsrcForkBytes)
{
fDocument->DoNeedDiskSpace(fFile, dataForkBytes, rsrcForkBytes);
if (fFile->IsRsrcForkOpen())
rsrcForkBytes = rsrcForkBytes + kRsrcFileOverhead;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAReadFile
pascal void TFileHandler::DoRead(Boolean forPrinting)
{
fDocument->DoRead(fFile, forPrinting);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::DoWrite(TFile* aFile,
Boolean makingCopy)
{
fDocument->DoWrite(aFile, makingCopy);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAFile
pascal OSErr TFileHandler::FileChanged(Boolean checkType)
{
FailInfo fi;
HParamBlockRec pb;
OSErr err = noErr;
if (fFileExists)
{
if (fi.Try())
{
FailOSErr(fFile->GetFileInfo(pb));
fi.Success();
}
else // Recover
{
this->Free();
fi.ReSignal();
}
if (checkType && (pb.fileParam.ioFlFndrInfo.fdType != fFile->fFileType))
err = errFTypeChanged;
else if (pb.fileParam.ioFlMdDat != fFile->GetModificationDate())
err = errFileChanged;
}
return err;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAFile
pascal Boolean TFileHandler::FileExists(void)
{
return fFileExists;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MADocumentRes
pascal TFile* TFileHandler::GetFile(void)
{
return fFile;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MADocumentRes
pascal void TFileHandler::GetFileName(Str63& aName)
{
if (fFile)
fFile->GetName(aName);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal Boolean TFileHandler::GetSaveInfo(CmdNumber,
Boolean copyFInfo,
CInfoPBRec& cInfo)
{
Boolean saveInfo = FALSE;
if (fFileExists && copyFInfo)
{
OSErr err = fFile->GetCatInfo(cInfo);
if (err == noErr)
saveInfo = TRUE;
}
// set the type and creator in case it has changed; the file might be on a file server
// and someone else could have changed the document
cInfo.hFileInfo.ioFlFndrInfo.fdType = fFile->fFileType;
cInfo.hFileInfo.ioFlFndrInfo.fdCreator = fFile->fCreator;
return saveInfo;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAFile
inline unsigned long __unsigned_long_abs_ (unsigned long a) { return a < 0 ? -a : a; }
pascal void TFileHandler::GetTempName(Str63& filename)
{
const short maxName = 31; //maximum name size to generate
const short maxNumber = 10; //maximum # digits of the random number
const short maxPrefix = maxName - maxNumber;
Str255 name;
short apRefnum;
Handle apParam;
unsigned long time;
// If the file is untitled, use the application name.
fFile->GetName((Str63 &)name);
if (name.IsEmpty())
GetAppParms(name, apRefnum, apParam);
filename = name;
// Check prefix length, and trim it down if too large.
if (filename.Length() > maxPrefix)
filename.Length() = (char)maxPrefix;
// Append a pseudo-random number.
GetDateTime(time);
NumToString(__unsigned_long_abs_(time ^ (TickCount() >> 16)), name);
filename += name;
// Check name length, and trim it down if too large.
if (filename.Length() > maxName)
filename.Length() = (char)maxName;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAFile
pascal Boolean TFileHandler::HasRsrcFork(void)
{
if (fFile)
return fFile->HasRsrcFork();
else
return FALSE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAReadFile
pascal void TFileHandler::ReadFile(Boolean forPrinting)
{
FailInfo fi;
if (fFile)
{
if (fi.Try())
{
FailOSErr(fFile->OpenFile());
fFileExists = TRUE;
this->DoRead(forPrinting);
fi.Success();
}
else // Recover
{
this->CloseFile();
fi.ReSignal();
}
FailOSErr(fFile->CloseFile(FALSE));
fFile->Modified(); // Set the modification date
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::RequestFileName(CmdNumber itsCmdNumber,
Boolean,
TFile* aFile)
{
StandardFileReply customReply;
SFReply reply;
short dlgID;
Str255 prompt;
Point dlgLoc;
ProcPtr dlgHook;
ProcPtr modalFilter;
Ptr activeList;
ProcPtr activateProc;
Ptr yourDataPtr;
TDocument * otherDoc;
Str255 filename;
Boolean goodReply;
OSErr err;
aFile->GetName((Str63 &)filename);
fDocument->SFPutParms(itsCmdNumber, prompt, filename, dlgID, dlgLoc, dlgHook, modalFilter, activeList, activateProc, yourDataPtr);
#if qDebug
gRsrcCheck = 0; //force immediate check
#endif
// Update all the windows to avoid a bug in Standard File in which you can't mount a disk
// correctly when window updates are pending. !!! (Is this still needed?
gApplication->UpdateAllWindows();
goodReply = FALSE;
if (qNeedsAliasMgr || gConfiguration.hasAliasMgr)
{
CustomPutFile(prompt, filename, customReply, dlgID, dlgLoc, (DlgHookYDProcPtr)dlgHook, (ModalFilterYDProcPtr)modalFilter, (short*)activeList, (ActivateYDProcPtr)activateProc, yourDataPtr);
if (customReply.sfGood)
{
aFile->IdentifyWithScript(customReply.sfFile, customReply.sfScript);
goodReply = TRUE;
}
}
else
{
SFPPutFile(dlgLoc, prompt, filename, (DlgHookProcPtr)dlgHook, reply, dlgID, (ModalFilterProcPtr)modalFilter);
if (reply.good)
{
FailOSErr(aFile->IdentifyByTrio(reply.vRefNum, 0, reply.fName));
goodReply = TRUE;
}
}
if (goodReply)
{
// See if there is an open document with the same name. If there is, tell it
// we're trying to save it again, which will ordinarily result in failure.
otherDoc = gApplication->AlreadyOpen(aFile);
if (otherDoc)
otherDoc->SaveAgain(itsCmdNumber, fDocument);
// User has already confirmed deleting target in this case, so trash file and get
// maximum disk space.
err = aFile->DeleteFile();
if ((err != noErr) && (err != fnfErr))
Failure(err, 0);
}
else
Failure(noErr, msgCancelled); // user cancelled
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::SaveFile(CmdNumber itsCmdNumber,
Boolean askForFilename,
Boolean copyFInfo,
Boolean makingCopy)
{
FailInfo fi;
TFile * theSaveFile = NULL;
long dataBytes = 0;
long rsrcBytes = 0;
long neededBlks;
long usedBlks;
long freeBlks;
long blkSize;
Boolean canSaveInPlace;
Str255 name;
OSErr err;
VOLATILE(theSaveFile);
VOLATILE(askForFilename);
VOLATILE(makingCopy);
if (fi.Try())
{
theSaveFile = NewFile();
if (askForFilename)
this->RequestFileName(itsCmdNumber, makingCopy, theSaveFile);
else
theSaveFile->IdentifyByFile(fFile);
theSaveFile->DefineFile(fFile->fFileType, fFile->fCreator, fFile->fUsesDataFork, fFile->fUsesRsrcFork, FALSE, FALSE);
theSaveFile->SetPermissions(fsRdWrPerm, fsRdWrPerm);// Since we intend to write to it
this->AboutToSaveFile(itsCmdNumber, makingCopy);
// Get information about the volume saving to
FailOSErr(theSaveFile->GetFreeBlocks(freeBlks));
// Don't fill the disk completely.
freeBlks--;
// compute size needed to save document
FailOSErr(theSaveFile->GetBlockSize(blkSize));
this->DoNeedDiskSpace(dataBytes, rsrcBytes);
neededBlks = NumBlocks(rsrcBytes, blkSize) + NumBlocks(dataBytes, blkSize);
// If there is enough space we're done. Save the file by the method specified
if (freeBlks >= neededBlks)
{
if ((fHowToSave == svtAskUser) || (fHowToSave == svtAlways))
this->SaveViaTemp(itsCmdNumber, makingCopy, copyFInfo, theSaveFile);
else
this->SaveInPlace(itsCmdNumber, makingCopy, copyFInfo, theSaveFile);
}
// Is there enough space to save the file in place?
else
{
canSaveInPlace = FALSE; // Default value
// See if we can save in place be recovering the space used by the existing file
err = theSaveFile->GetPhysicalSize(dataBytes, rsrcBytes);
if (err == noErr)
{
usedBlks = NumBlocks(dataBytes, blkSize) + NumBlocks(rsrcBytes, blkSize);
if (neededBlks <= usedBlks + freeBlks)
{
// Saving in place purges the existing file. Should we ask before going ahead?
if ((fHowToSave == svtAskUser) || (fHowToSave == sipAskUser))
{
theSaveFile->GetName((Str63 &)name);
ParamText(name, "", "", "");
if (MacAppAlert(phPurgeOld, NULL) == kYesButton)
canSaveInPlace = TRUE;
else
Failure(noErr, msgCancelled);
}
else if (fHowToSave == sipAlways)
canSaveInPlace = TRUE;
}
}
// If no file to recover space from, signal disk full error. Otherwise just display error
else if (err != fnfErr)
Failure(err, 0);
if (canSaveInPlace)
this->SaveInPlace(itsCmdNumber, makingCopy, copyFInfo, theSaveFile);
else
Failure(dskFulErr, 0);
}
#if qDebugMsg
err = theSaveFile->GetPhysicalSize(dataBytes, rsrcBytes);
if (err == noErr)
{
usedBlks = NumBlocks(dataBytes, blkSize) + NumBlocks(dataBytes, blkSize);
if (usedBlks != neededBlks)
{
fprintf(stderr, "In TFileHandler.Save: DoNeedDiskSpace estimated disk space incorrectly.\n");
fprintf(stderr, "estimated # disk blocks = %ld\n", neededBlks);
fprintf(stderr, " actual # disk blocks = %ld\n", usedBlks);
}
}
#endif
if (!makingCopy)
{
theSaveFile->GetName((Str63 &)name);
fDocument->FileHasBeenSaved(name);
fFileExists = TRUE;
fFile->IdentifyByFile(theSaveFile);
fFile->Modified();
FailOSErr(fFile->OpenFile());
}
fi.Success();
}
else // Recover
{
long newMsg;
if (theSaveFile)
{
err = theSaveFile->FlushVolume();
if (fi.message == 0)
theSaveFile->GetName((Str63 &)gErrorParm3);
theSaveFile = (TFile *)FreeIfObject(theSaveFile);
}
if (!askForFilename)
newMsg = msgSaveFailed;
else if (makingCopy)
newMsg = msgSaveCopyFailed;
else
newMsg = msgSaveAsFailed;
FailNewMessage(fi.error, fi.message, newMsg);
fi.ReSignal();
}
err = theSaveFile->FlushVolume();
theSaveFile->Free();
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::SaveInPlace(CmdNumber itsCmdNumber,
Boolean makingCopy,
Boolean copyFInfo,
TFile* itsFile)
{
FailInfo fi;
CInfoPBRec cInfo;
Boolean validInfo;
OSErr err;
VOLATILE(itsFile);
VOLATILE(validInfo);
VOLATILE(makingCopy);
validInfo = this->GetSaveInfo(itsCmdNumber, copyFInfo, cInfo);
this->CloseFile(); // close the file
err = fFile->DeleteFile();
if ((err != noErr) && (err != fnfErr))
Failure(err, 0);
if (fi.Try())
{
FailOSErr(itsFile->CreateFile());
if (validInfo) // Change attributes of itsFile?
FailOSErr(itsFile->SetCatInfo(cInfo));
FailOSErr(itsFile->OpenFile());
this->DoWrite(itsFile, makingCopy);
fi.Success();
}
else // Recover
{
OSErr err;
err = itsFile->CloseFile(TRUE);
#if qDebugMsg
if (err != noErr)
fprintf(stderr, "In HdlMkNewCopy: error from itsFile.CloseFile is %d\n", err);
#endif
err = itsFile->DeleteFile();
#if qDebugMsg
if ((err != noErr) && (err != fnfErr))
fprintf(stderr, "In HdlMkNewCopy: error from itsFile.DeleteFile is %d\n", err);
#endif
fi.ReSignal();
}
FailOSErr(itsFile->CloseFile(TRUE));
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAWriteFile
pascal void TFileHandler::SaveViaTemp(CmdNumber itsCmdNumber,
Boolean makingCopy,
Boolean copyFInfo,
TFile* itsFile)
{
FailInfo fi;
Boolean validInfo;
CInfoPBRec cInfo;
FSSpec saveFileSpec;
Str63 tmpName;
short tmpVRefNum;
long tmpDirID;
OSErr err;
VOLATILE(itsFile);
VOLATILE(makingCopy);
validInfo = this->GetSaveInfo(itsCmdNumber, copyFInfo, cInfo);
itsFile->GetFileSpec(saveFileSpec); // Save file spec since it may be clobbered
this->GetTempName(tmpName);
// If we are using the folder manager, put in the temporary folder, creating if necessary
if (qNeedsFolderMgr || gConfiguration.hasFolderMgr)
{
FailOSErr(FindFolder(saveFileSpec.vRefNum, kTemporaryFolderType, kCreateFolder, tmpVRefNum, tmpDirID));
FailOSErr(itsFile->IdentifyByTrio(tmpVRefNum, tmpDirID, tmpName));
}
else
itsFile->SetName(tmpName);
if (fi.Try())
{
FailOSErr(itsFile->CreateFile());
if (validInfo) // Change attributes of itsFile??
FailOSErr(itsFile->SetCatInfo(cInfo));
FailOSErr(itsFile->OpenFile());
this->DoWrite(itsFile, makingCopy);
fi.Success();
}
else // Recover
{
OSErr err;
err = itsFile->CloseFile(TRUE);
#if qDebugMsg
if (err != noErr)
fprintf(stderr, "In HdlMkNewCopy: error from CloseFile is %d", err);
#endif
err = itsFile->DeleteFile();
#if qDebugMsg
if ((err != noErr) && (err != fnfErr))
fprintf(stderr, "In HdlMakeCopy: error from itsFile.DeleteFile is %d", err);
#endif
}
FailOSErr(itsFile->CloseFile(TRUE));
if (!makingCopy)
this->CloseFile(); // Close the documents file
if (fi.Try())
{
if (qNeedsFolderMgr || gConfiguration.hasFolderMgr)
{
if (fFileExists && copyFInfo)
{
// Exchange the existing file for the one in the temporary folder…
FailOSErr(itsFile->ExchangeFiles(fFile));
// and delete the one left in the temporary folder
err = itsFile->DeleteFile();
if ((err != noErr) && (err != fnfErr))
Failure(err, 0);
}
else // The temp file was created in the temporary directory. Move it back where it belongs
FailOSErr(itsFile->MoveAndRename(saveFileSpec));
}
else
{
itsFile->SetName(saveFileSpec.name);// Set to original name…
err = itsFile->DeleteFile(); // and delete it if it exists…
if ((err != noErr) && (err != fnfErr))
Failure(err, 0);
itsFile->SetName(tmpName); // and set it back for renaming
FailOSErr(itsFile->RenameFile(saveFileSpec.name));
}
// Identify the file again since it may have changed if it was saved in a temporary folder
itsFile->Identify(saveFileSpec);
fi.Success();
}
else // Recover
{
FailInfo newfi;
if (fFileExists &&!makingCopy)
{
if (newfi.Try())
{
FailOSErr(fFile->OpenFile());
newfi.Success();
}
else // Recover
{
// If reopen attempt fails, make sure original error gets through.
Failure(newfi.error, newfi.message);
newfi.ReSignal();
}
}
fi.ReSignal();
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment MADocumentRes
pascal void TFileHandler::SetFileName(const Str63& aName)
{
if (fFile)
fFile->SetName(aName);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAFields
pascal void TFileHandler::Fields(TObject* obj)
{
obj->DoToField("TFileHandler", (Ptr)NULL, bClass);
obj->DoToField("fDocument", (Ptr) & fDocument, bObject);
obj->DoToField("fFile", (Ptr) & fFile, bObject);
obj->DoToField("fFileExists", (Ptr) & fFileExists, bBoolean);
obj->DoToField("fHowToSave", (Ptr) & fHowToSave, bByte);
inherited::Fields(obj);
}